package server.model;

import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.rmi.NotBoundException;
import java.rmi.AccessException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import java.sql.SQLTimeoutException;
import java.util.Map;
import java.util.HashMap;
import client.model.ClientInterface;

public class ServerImpl implements ServerInterface{


	public final static String SERVICE_NAME = "server";	
	public final static int PORT = 12345;
	Registry registry;
	Connection connection;
	Statement statement;
	ResultSet resultSet;
	Map<String,ClientInterface> logins;
	static ServerImpl instance;

	String mysqlUrl = "jdbc:mysql://192.168.1.34/progapps?user=progapps",
		registerString = "insert into users values (0,?,?,?,?,?,?)",
		getQuestionForString = "select question from"+
			" questions natural join users where"+
			" username=?",
		getPasswordString = "select password from users where username=?" +
			" and answer=?",
		loginString = "select userid from users where username=? and password=?";

	private ServerImpl(){
		try{
			registry = LocateRegistry.createRegistry(PORT);
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
	}

	public static ServerImpl getInstance(){
		if(instance==null){
			instance = new ServerImpl();
		}
		return instance;
	}

	public void close(){
		if(connection!=null&&registry!=null){
			try{
				connection.close();
				System.out.println("sql connection closed");
				if(registry.lookup(SERVICE_NAME)!=null){
					System.out.println("Unbinding servce..");
					registry.unbind(SERVICE_NAME);
				}
				//UnicastRemoteObject.unexportObject(this, true);
			}catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
	}

	void open(){
		try{
			ServerInterface stub = (ServerInterface) UnicastRemoteObject.exportObject(this,0);
			registry = LocateRegistry.getRegistry(PORT);
			registry.rebind(SERVICE_NAME, stub);
			System.out.println("serv bound");
		
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			connection = DriverManager.getConnection(mysqlUrl);
			System.out.println("connection ok");

			logins = new HashMap<String,ClientInterface>();
			System.out.println("now accepting logins");
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
	}	
	
	public boolean register(String lastname,
		String firstname, String username,
		String password, int questionid,
		String answer) throws RemoteException{
		boolean success = false;
		try(PreparedStatement registerStatement =
			connection.prepareStatement(registerString)){
			registerStatement.setString(1, lastname);
			registerStatement.setString(2, firstname);
			registerStatement.setString(3, username);
			registerStatement.setString(4, password);
			registerStatement.setInt(5, questionid);
			registerStatement.setString(6, answer);
			int r=registerStatement.executeUpdate();
			switch(r){
				case 0: System.out.println("none"); break;
				default: System.out.println("row count: "+r);
			}
			success = true;
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
		return success;
	}

	public String getQuestionFor(String username)
		throws RemoteException{
		String question = "";
		try(PreparedStatement getQuestionForStatement = 
			connection.prepareStatement(getQuestionForString)){
			getQuestionForStatement.setString(1, username);
			resultSet = getQuestionForStatement.executeQuery();
			if(resultSet.first()){
				question = resultSet.getString("question");
			}
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
		return question;
	}

	public String getPassword(String username, String answer)
		throws RemoteException{
		String password = "";
		try(PreparedStatement getPasswordStatement = 
			connection.prepareStatement(getPasswordString)){
			getPasswordStatement.setString(1, username);
			getPasswordStatement.setString(2, answer);
			resultSet = getPasswordStatement.executeQuery();
			if(resultSet.first()){
				password = resultSet.getString("password");
			}
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
		return password;
	}

	public boolean login(String username, String password,
		ClientInterface client)throws RemoteException{
		boolean loggedin = false;
		try(PreparedStatement loginStatement =
			connection.prepareStatement(loginString)){
			loginStatement.setString(1, username);
			loginStatement.setString(2, password);
			ResultSet rs = loginStatement.executeQuery();
			if(rs.first()){
				if(logins.put(username, client)==null){
					loggedin = true;
				}
			}
			rs.close();
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
		return loggedin;
	}

	public void logout(String username) throws RemoteException{
		logins.remove(username);
	}
	public void sendTo(String username,
		String message) throws RemoteException{}
	public void sentToGroup(String group,
		String message) throws RemoteException{}
	public void sendMessage(/*Message message*/)
		throws RemoteException{}
}